package utils

import (
	"context"
	"sync"

	"github.com/gin-gonic/gin"
)

// contextKey 上下文键类型，避免键名冲突
type contextKey string

const (
	// UserIDKey 用户ID在上下文中的键名
	UserIDKey contextKey = "userId"
	// UsernameKey 用户名在上下文中的键名
	UsernameKey contextKey = "username"
	// TenantIDKey 租户ID在上下文中的键名
	TenantIDKey contextKey = "tenantId"
)

// UserInfo 用户信息结构体
type UserInfo struct {
	UserID   uint
	Username string
	TenantID uint
}

// 全局变量存储当前请求的上下文
var (
	currentContext      context.Context
	currentContextMutex sync.RWMutex
)

// ==================== Gin中间件和全局上下文管理 ====================

// ContextMiddleware Gin中间件，自动设置当前上下文
func ContextMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 将Gin上下文转换为标准Context
		ctx := GinToContext(c)

		// 设置当前上下文
		SetCurrentContext(ctx)

		// 继续处理请求
		c.Next()

		// 请求完成后清除上下文
		ClearCurrentContext()
	}
}

// SetCurrentContext 设置当前上下文
func SetCurrentContext(ctx context.Context) {
	currentContextMutex.Lock()
	defer currentContextMutex.Unlock()
	currentContext = ctx
}

// ClearCurrentContext 清除当前上下文
func ClearCurrentContext() {
	currentContextMutex.Lock()
	defer currentContextMutex.Unlock()
	currentContext = nil
}

// GetCurrentContext 获取当前上下文
func GetCurrentContext() context.Context {
	currentContextMutex.RLock()
	defer currentContextMutex.RUnlock()

	if currentContext != nil {
		return currentContext
	}
	return context.Background()
}

// ==================== 自动获取当前用户信息 ====================

// GetCurrentUser 获取当前用户信息（自动从当前上下文获取）
func GetCurrentUser() *UserInfo {
	ctx := GetCurrentContext()
	return GetUserInfoFromContext(ctx)
}

// GetCurrentUserID 获取当前用户ID
func GetCurrentUserID() uint {
	user := GetCurrentUser()
	return user.UserID
}

// GetCurrentUsername 获取当前用户名
func GetCurrentUsername() string {
	user := GetCurrentUser()
	return user.Username
}

// GetCurrentTenantID 获取当前租户ID
func GetCurrentTenantID() uint {
	user := GetCurrentUser()
	return user.TenantID
}

// IsUserLoggedIn 检查当前用户是否已登录
func IsUserLoggedIn() bool {
	user := GetCurrentUser()
	return user.UserID > 0 && user.TenantID > 0
}

// MustGetCurrentUser 强制获取当前用户信息，未登录时panic
func MustGetCurrentUser() *UserInfo {
	user := GetCurrentUser()
	if user.UserID == 0 || user.TenantID == 0 {
		panic("用户未登录或登录信息无效")
	}
	return user
}

// MustGetCurrentUserID 强制获取当前用户ID，未登录时panic
func MustGetCurrentUserID() uint {
	userID := GetCurrentUserID()
	if userID == 0 {
		panic("用户未登录或登录信息无效")
	}
	return userID
}

// MustGetCurrentTenantID 强制获取当前租户ID，未登录时panic
func MustGetCurrentTenantID() uint {
	tenantID := GetCurrentTenantID()
	if tenantID == 0 {
		panic("用户未登录或登录信息无效")
	}
	return tenantID
}

// ==================== 上下文转换工具 ====================

// GinToContext 将Gin上下文转换为标准Context
func GinToContext(c *gin.Context) context.Context {
	ctx := context.Background()

	// 从Gin上下文中获取用户信息并存入标准Context
	if userID, exists := c.Get("userId"); exists {
		if id, ok := userID.(uint); ok {
			ctx = context.WithValue(ctx, UserIDKey, id)
		}
	}

	if username, exists := c.Get("username"); exists {
		if name, ok := username.(string); ok {
			ctx = context.WithValue(ctx, UsernameKey, name)
		}
	}

	if tenantID, exists := c.Get("tenantId"); exists {
		if id, ok := tenantID.(uint); ok {
			ctx = context.WithValue(ctx, TenantIDKey, id)
		}
	}

	return ctx
}

// GetUserInfoFromContext 从标准Context中获取用户信息
func GetUserInfoFromContext(ctx context.Context) *UserInfo {
	var userID, tenantID uint
	var username string

	if val := ctx.Value(UserIDKey); val != nil {
		if id, ok := val.(uint); ok {
			userID = id
		}
	}

	if val := ctx.Value(UsernameKey); val != nil {
		if name, ok := val.(string); ok {
			username = name
		}
	}

	if val := ctx.Value(TenantIDKey); val != nil {
		if id, ok := val.(uint); ok {
			tenantID = id
		}
	}

	return &UserInfo{
		UserID:   userID,
		Username: username,
		TenantID: tenantID,
	}
}

// ==================== 显式上下文管理（兼容旧代码） ====================

// ContextManager 上下文管理器（兼容旧代码）
type ContextManager struct{}

// NewContextManager 创建上下文管理器实例（兼容旧代码）
func NewContextManager() *ContextManager {
	return &ContextManager{}
}

// GinToContext 将Gin上下文转换为标准Context（兼容旧代码）
func (cm *ContextManager) GinToContext(c *gin.Context) context.Context {
	return GinToContext(c)
}

// GetUserInfoFromContext 从标准Context中获取用户信息（兼容旧代码）
func (cm *ContextManager) GetUserInfoFromContext(ctx context.Context) *UserInfo {
	return GetUserInfoFromContext(ctx)
}

// GetUserIDFromContext 从标准Context中获取用户ID（兼容旧代码）
func (cm *ContextManager) GetUserIDFromContext(ctx context.Context) uint {
	user := GetUserInfoFromContext(ctx)
	return user.UserID
}

// GetUsernameFromContext 从标准Context中获取用户名（兼容旧代码）
func (cm *ContextManager) GetUsernameFromContext(ctx context.Context) string {
	user := GetUserInfoFromContext(ctx)
	return user.Username
}

// GetTenantIDFromContext 从标准Context中获取租户ID（兼容旧代码）
func (cm *ContextManager) GetTenantIDFromContext(ctx context.Context) uint {
	user := GetUserInfoFromContext(ctx)
	return user.TenantID
}

// GetCurrentUserFromContext 从标准Context中获取完整用户信息（兼容旧代码）
func (cm *ContextManager) GetCurrentUserFromContext(ctx context.Context) *UserInfo {
	return GetUserInfoFromContext(ctx)
}

// IsUserLoggedInContext 检查Context中用户是否已登录（兼容旧代码）
func (cm *ContextManager) IsUserLoggedInContext(ctx context.Context) bool {
	user := GetUserInfoFromContext(ctx)
	return user.UserID > 0 && user.TenantID > 0
}
